package river_city_ransom.contracts;

import exceptions.ComposantError;
import exceptions.InvariantError;
import exceptions.PostconditionError;
import exceptions.PreconditionError;
import river_city_ransom.decorators.Equipable_D;
import river_city_ransom.services.Dimensions;
import river_city_ransom.services.Equipable;
import river_city_ransom.services.Position;
import tools.Toolbox;


public class Equipable_C extends Equipable_D {
	public Equipable_C(Equipable delegate) {
		super(delegate);
	}
	
	/** __________________________________________________________ INVARIANTS */
	public void checkInvariants() throws ComposantError {
		boolean inv;
//		inv -1 <= estJete(E) <= 1
		inv = -1 <= estJete() && estJete() <= 1;
		if(!inv) {
			throw new InvariantError("-1 <= estJete(E) <= 1");
		}
	}
	
	/** _________________________________________________________ OBSERVATORS */
	@Override
	public Dimensions dimensions() {
		return super.dimensions();
	}
	
	@Override
	public boolean estEquipable() {
		return super.estEquipable();
	}
	
	@Override
	public boolean estPorte() {
		return super.estPorte();
	}
	
	@Override
	public int estJete() {
		return super.estJete();
	}
	
	@Override
	public Position position() {
		return super.position();
	}
	
	/** ___________________________________________________________ OPERATORS */
	@Override
	public void etreRamasse() throws ComposantError {
		boolean pre;
//		pre etreRamasse(E) require estEquipable(E) ^ !estPorte(E)
		pre = estEquipable() && !estPorte();
		if(!pre) {
			throw new PreconditionError("etreRamasse(E) require estEquipable(E) ^ !estPorte(E)");
		}
		
		Position p_pre = position();
		
		checkInvariants();
		
		delegate().etreRamasse();
		
		checkInvariants();
		
		boolean post;
//		post estPorte(etreRamasse(E)) = true
		post = estPorte() == true;
		if(!post) {
			throw new PostconditionError("estPorte(etreRamasse(E)) = true");
		}
//		post estJete(etreRamasse(E)) = 0
		post = estJete() == 0;
		if(!post) {
			throw new PostconditionError("estJete(etreRamasse(E)) = 0");
		}
//		post position(etreRamasse(E)) = position(E)
		post = Toolbox.equals(position(), p_pre);
		if(!post) {
			throw new PostconditionError("position(etreRamasse(E)) = position(E)");
		}
	}

	@Override
	public void etreJete(boolean d) throws ComposantError {
		boolean pre;
//		pre etreJete(E) require estPorte(E)
		pre = estPorte();
		if(!pre) {
			throw new PreconditionError("etreJete(E) require estPorte(E)");
		}
		
		Position p_pre = position();
		
		checkInvariants();
		
		delegate().etreJete(d);
		
		checkInvariants();
		
		boolean post;
//		post estPorte(etreJete(E, d)) = false
		post = estPorte() == false;
		if(!post) {
			throw new PostconditionError("estPorte(etreJete(E, d)) = false");
		}
//		post estJete(etreJete(E, d)) = { 1 si d
//									   { -1 sinon
		if(d) {
			post = estJete() == 1;
			if(!post) {
				throw new PostconditionError("d -> estJete(etreJete(E, d)) = 1");
			}
		}
		else {
			post = estJete() == -1;
			if(!post) {
				throw new PostconditionError("!d -> estJete(etreJete(E, d)) = -1");
			}
		}
//		post position(etreJete(E, d)) = position(E)
		post = Toolbox.equals(position(), p_pre);
		if(!post) {
			throw new PostconditionError("position(etreJete(E, d)) = position(E)");
		}
	}
}
